ACM POJ 2245Lotto解题报告
http://poj.org/problem?id=2245
Lotto
在玩德国游戏Lotto时,要从集合{1,2,……,49}中取出六个数。
一个非常流行的玩法(尽管这种玩法并不能增加你赢的机会)是从这49个数字中取出k个数字(6<k)组成子集S。然后玩游戏的时候仅从S中取出数字。
例如,当k=8,S=1,2,3,5,8,13,21,34时,有28种可能的游戏:
[1,2,3,5,8,13],[1,2,3,5,8,21],[1,2,3,5,8,34],[1,2,3,5,13,21],……,[3,5,8,13,21,34]。
编一个程序,读入k的值和集合S,打印仅从S中取数的所有可能游戏。
输入
输入文件包括一个或多个测试情形。
每种情形一行,由多个整数组成,整数之间用空格分隔。行首整数即为k值(6<k<13)。
接着是用于描述集合S的k个整数,全部以升序排列。
在k的位置输入零(0)即表示输入结束。
输出:
对于每一个测试情形,打印出所有可能游戏,每个游戏一行。
每个游戏中的数字必须以升序排列,每两个之间用一个空格分隔。而这些游戏要用类似于字典编纂的方式排序,也就是说,先对最低位排序,然后是第二低位,依次类推,就像输出举例中演示的那样。
输入样例:
7 1 2 3 4 5 6 7
8 1 2 3 5 8 13 21 34
0
输出样例
1 2 3 4 5 6
1 2 3 4 5 7
1 2 3 4 6 7
1 2 3 5 6 7
1 2 4 5 6 7
1 3 4 5 6 7
2 3 4 5 6 7
1 2 3 5 8 13
1 2 3 5 8 21
1 2 3 5 8 34
1 2 3 5 13 21
1 2 3 5 13 34
1 2 3 5 21 34
1 2 3 8 13 21
1 2 3 8 13 34
1 2 3 8 21 34
1 2 3 13 21 34
1 2 5 8 13 21
1 2 5 8 13 34
1 2 5 8 21 34
1 2 5 13 21 34
1 2 8 13 21 34
1 3 5 8 13 21
1 3 5 8 13 34
1 3 5 8 21 34
1 3 5 13 21 34
1 3 8 13 21 34
1 5 8 13 21 34
2 3 5 8 13 21
2 3 5 8 13 34
2 3 5 8 21 34
2 3 5 13 21 34
2 3 8 13 21 34
2 5 8 13 21 34
3 5 8 13 21 34
本题就是产生组合数的方法。
#include<stdio.h>
#include<iostream>
using namespace std;
#define MAXN 20
int p[MAXN];
void print(int *a,int m) //输出
{
int i,cnt;
for(i=0;i<m-1;i++) {cnt=a[i];cout<<p[cnt]<<' ';}
cnt=a[m-1];
cout<<p[cnt]<<endl;
}
//先是产生1,2,3,4,5,6,7......这样的组合数,再利用下标输出需要的组合数
void GenComb(int *a,int n,int m)//产生下一个组合数
{
int i,j,t;
print(a,m);
for(j=m-1;j>=0;j--)
if(a[j]<n-m+j+1)break;
t=a[j];
for(i=0;i<=m-j-1;i++)
a[j+i]=t+i+1;
}
void GenAllComb(int *a,int n,int m)
{
int index;
for(index=0;index<m;index++)a[index]=index+1;//初始化,产生1,2,3...这样的数列
index=0;
while(index<=n-m)//index指向的是第一个组合数 的小标,当index大于n-m时说明,已经到达尾部。
{
GenComb(a,n,m);
if(a[0]>index+1)index++;
}
}
int main()
{
int n,m=6,a[MAXN],i;
int first=0;//POJ上的题目要求最后一个不要产生空格,故除第一组外其余前面产生空格
while(cin>>n,n)
{
if(first) cout<<endl;
first=1;
for(i=1;i<=n;i++) cin>>p[i];
GenAllComb(a,n,m);
}
return 0;
}
(此程序在POJ上GCC++通不过,用C++,Accept了。。。 奇怪了)
#include<stdio.h>
#include<iostream>
using namespace std;
#define MAXN 20
int p[MAXN];
void print(int *a,int m) //输出
{
int i,cnt;
for(i=0;i<m-1;i++) {cnt=a[i];cout<<p[cnt]<<' ';}
cnt=a[m-1];
cout<<p[cnt]<<endl;
}
//先是产生1,2,3,4,5,6,7......这样的组合数,再利用下标输出需要的组合数
void GenComb(int *a,int n,int m)//产生下一个组合数
{
int i,j,t;
print(a,m);
for(j=m-1;j>=0;j--)
if(a[j]<n-m+j+1)break;
t=a[j];
for(i=0;i<=m-j-1;i++)
a[j+i]=t+i+1;
}
void GenAllComb(int *a,int n,int m)
{
int index;
for(index=0;index<m;index++)a[index]=index+1;//初始化,产生1,2,3...这样的数列
index=0;
while(index<=n-m)//index指向的是第一个组合数 的小标,当index大于n-m时说明,已经到达尾部。
{
GenComb(a,n,m);
if(a[0]>index+1)index++;
}
}
int main()
{
int n,m=6,a[MAXN],i;
int first=0;//POJ上的题目要求最后一个不要产生空格,故除第一组外其余前面产生空格
while(cin>>n,n)
{
if(first) cout<<endl;
first=1;
for(i=1;i<=n;i++) cin>>p[i];
GenAllComb(a,n,m);
}
return 0;
}
下面的程序是学习了网上的写出来的,比较简洁,推荐!!!
#include<stdio.h> #include<string.h>//memset函数头文件 int K;//每一组数的个数 int num[13]; int chosed[13]; void find(int st,int n) { int i,first; if(n==6) { first=1; for(i=0;i<K;i++) { if(chosed[i]) { if(first==1) {printf("%d",num[i]);first=0;} else printf(" %d",num[i]); } } printf("\n");return; } for(i=st;i<K;i++) { if(!chosed[i]) { chosed[i]=1; find(i+1,n+1); chosed[i]=0; } } } int main() { int i,first=1; while(scanf("%d",&K)!=EOF&&K) { for(i=0;i<K;i++) scanf("%d",&num[i]); if(first==1)first=0; else printf("\n"); memset(chosed,0,sizeof(chosed)); find(0,0); } return 0; }